﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ScaffoldIt.Configuration;
using System.IO;
using ScaffoldIt.Commands;

namespace ScaffoldIt
{
    public partial class FormScaffoldItConfig : UserControl
    {
        private ScaffoldItConfig _config;
        private Preset _currentpreset;

        public delegate string[] GetProjectsHandler();

        public delegate void OpenFileHandler(string filename);

        public delegate void SaveConfigHandler(ScaffoldIt.Configuration.ScaffoldItConfig cfg);

        public GetProjectsHandler OnGetProject;

        public SaveConfigHandler OnSaveConfig;

        public OpenFileHandler OnOpenFile;

        public bool HasConfig
        {
            get
            {
                return _config != null;
            }
        }

        public string ConfigFile
        {
            get
            {
                if (_config == null) return null;

                return _config.FileName;
            }
        }

        public FormScaffoldItConfig()
        {
            InitializeComponent();
            this.Enabled = false;
        }

        public string[] GetProjects()
        {
            if (OnGetProject != null)
                return OnGetProject();

            return new string[] { "Project 1", "Project 2" };
        }

        public void Init(ScaffoldItConfig config)
        {
            _config = config;
            this.Enabled = false;
            treeViewParameters.Nodes.Clear();
            treeViewTemplates.Nodes.Clear();
            treeViewPresets.Nodes.Clear();
            comboPresets.Items.Clear();

            if (config == null) return;
            this.Enabled = true;

            foreach (var parameter in config.Parameters)
            {
                AddRootParameter(parameter);
            }

            foreach (var category in config.Categories)
            {
                AddNodeCategory(treeViewTemplates.Nodes, category);
            }

            foreach (var preset in config.Presets)
            {
                comboPresets.Items.Add(preset);
            }
            treeViewParameters.Sort();
            treeViewTemplates.Sort();
                    
        }

        private void AddRootParameter(Parameter parameter)
        {
            var node = this.treeViewParameters.Nodes.Add(parameter.Title + " (" + parameter.Code + ")");
            node.ImageIndex = 2;
            node.SelectedImageIndex = 2;
            node.ToolTipText = parameter.Description;
            if (parameter.IsGlobal)
            {
                node.ImageIndex = 3;
                node.SelectedImageIndex = 3;
            }

            node.Tag = parameter;
        }

        private void AddNodeCategory(TreeNodeCollection parent, Category category)
        {
            var node = parent.Add(category.Name);
            node.Tag = category;
            node.ImageIndex = 0;
            node.SelectedImageIndex = 0;
            node.ToolTipText = category.Description;

            foreach (var childcat in category.Categories)
            {
                this.AddNodeCategory(node.Nodes, childcat);
            }

            foreach (var template in category.Templates)
            {
                this.AddNodeTemplate(node.Nodes, template);
            }
        }

        private void AddNodeTemplate(TreeNodeCollection parent, Template template)
        {
            var node = parent.Add(template.Name);
            node.Tag = template;
            node.ImageIndex = 1;
            node.SelectedImageIndex = 1;
            node.ToolTipText = template.Description;

            foreach (var parameter in template.Parameters)
            {
                this.AddNodeParameter(node.Nodes, parameter);
            }
        }

        private void AddNodeParameter(TreeNodeCollection parent, Parameter parameter)
        {
            var srcParameter = _config.Parameters.Find(p => p.Code == parameter.Code);
            var node = parent.Add(srcParameter.Title + " (" + parameter.Code + ")");
            node.Tag = parameter;
            node.ImageIndex = 2;
            node.SelectedImageIndex = 2;
            node.ToolTipText = srcParameter.Description;
        }

        private void comboPresets_SelectedIndexChanged(object sender, EventArgs e)
        {
            treeViewPresets.Nodes.Clear();
            _currentpreset = (Preset)comboPresets.SelectedItem;

            if (_currentpreset != null)
            {
                foreach (var cat in _currentpreset.Categories)
                {
                    this.AddNodePresetCat(treeViewPresets.Nodes, cat);
                }
                
                treeViewPresets.ExpandAll();
                treeViewPresets.Sort();
            }
        }

        private void AddNodePresetCat(TreeNodeCollection parent, PresetCategory cat)
        {
            var node = parent.Add(cat.Category);
            node.ImageIndex = 0;
            node.SelectedImageIndex = 0;
            node.Tag = cat;

            foreach (var childcat in cat.Categories)
            {
                this.AddNodePresetCat(node.Nodes, childcat);
            }

            foreach (var templ in cat.GetTemplates())
            {
                var childnode = node.Nodes.Add(templ);
                childnode.ImageIndex = 1;
                childnode.SelectedImageIndex = 1;
                childnode.Tag = templ;
            }
        }

        void HideAllChilds(Control ctrl)
        {
            foreach (Control control in ctrl.Controls)
            {
                control.Visible = false;
                this.HideAllChilds(control);
            }
        }

        private void ctxMenuTreeTemplate_Opening(object sender, CancelEventArgs e)
        {

        }

        private void ctxMenuTreeTemplate_Opened(object sender, EventArgs e)
        {
            var menu = sender as ContextMenuStrip;
            var selectedNode = treeViewTemplates.SelectedNode;

            mnuTemplAddCategory.Visible = false;
            mnuTemplAddTemplate.Visible = false;
            mnuTemplRemoveCategory.Visible = false;
            mnuTemplEdit.Visible = false;
            mnuTemplRemoveTemplate.Visible = false;
            mnuTemplEdit.Visible = false;
            mnuTemplRemoveParameter.Visible = false;
            mnuTemplView.Visible = false;

            mnuTemplAddRootCat.Visible = true;

            if (selectedNode.Tag is Category)
            {
                mnuTemplAddCategory.Visible = true;
                mnuTemplAddTemplate.Visible = true;
                mnuTemplRemoveCategory.Visible = true;
                mnuTemplEdit.Visible = true;
            }
            else if (selectedNode.Tag is Template)
            {
                mnuTemplRemoveTemplate.Visible = true;
                mnuTemplEdit.Visible = true;
                mnuTemplView.Visible = true;
            }
            else if (selectedNode.Tag is Parameter)
            {
                mnuTemplRemoveParameter.Visible = true;
            }
        }

        private void treeViewParameters_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (treeViewParameters.SelectedNode != null)
            {
                var data = treeViewParameters.SelectedNode.Tag;
                DoDragDrop(data, DragDropEffects.Copy);
            }
        }

        private void treeViewTemplates_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (treeViewTemplates.SelectedNode != null)
            {
                var data = treeViewTemplates.SelectedNode.Tag;
                if (!(data is Parameter))
                    DoDragDrop("Templates", DragDropEffects.Copy);
            }
        }

        private void treeViewTemplates_DragOver(object sender, DragEventArgs e)
        {
            if (!treeViewParameters.SelectedNodes.Any<Parameter>(p => p.IsGlobal))
            {
                Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
                var node = treeViewTemplates.GetNodeAt(pt);
                if (node != null && node.Tag is Template)
                {
                    e.Effect = DragDropEffects.Copy;
                    return;
                }
            }

            e.Effect = DragDropEffects.None;
        }

        private void treeViewTemplates_DragDrop(object sender, DragEventArgs e)
        {
            if (!treeViewParameters.SelectedNodes.Any<Parameter>(p => p.IsGlobal))
            {
                Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
                var node = treeViewTemplates.GetNodeAt(pt);
                if (node != null && node.Tag is Template)
                {
                    foreach (var parameter in treeViewParameters.SelectedNodes.Select(n => n.Tag as Parameter))
                    {
                        var template = node.Tag as Template;
                        var child = new Parameter() { Code = parameter.Code, Value = parameter.Value };
                        template.Parameters.Add(child);
                        this.AddNodeParameter(
                            node.Nodes, child);
                    }
                    
                    node.Expand();
                    this.AutoSave();
                }
            }
        }

        private void treeViewTemplates_DragEnter(object sender, DragEventArgs e)
        {
            if (treeViewParameters.SelectedNodes.Any<Parameter>(p => p.IsGlobal))
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            if (e.Data.GetDataPresent(typeof(Parameter)))
                e.Effect = DragDropEffects.Copy;
        }



        private void treeViewPresets_DragEnter(object sender, DragEventArgs e)
        {
            if (comboPresets.SelectedItem != null && e.Data.GetDataPresent(typeof(string)))
            {
                var data = (string)e.Data.GetData(typeof(string));
                if (data == "Templates")
                    e.Effect = DragDropEffects.Copy;
            }
        }

        private void treeViewPresets_DragDrop(object sender, DragEventArgs e)
        {
            if (comboPresets.SelectedItem != null && e.Data.GetDataPresent(typeof(string)))
            {
                var data = (string)e.Data.GetData(typeof(string));
                if (data == "Templates")
                {
                    if (TreeViewHelpers.Sync(comboPresets.SelectedItem as Preset, treeViewPresets, treeViewTemplates.SelectedNodes))
                    {
                        treeViewPresets.Sort(); 
                        treeViewPresets.ExpandAll();
                        
                        this.AutoSave();
                    }
                }
            }
        }

        private void treeViewParameters_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.mnuParamsEdit_Click(sender, e);
        }

        private void treeViewTemplates_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            mnuTemplEdit_Click(sender, e);
        }

        private bool EditTemplateParameter(Parameter parameter, TreeNode parameterNode)
        {
            if (FormEditTemplateParameter.EditParameter(parameter))
            {
                var srcParameter = _config.Parameters.Find(p => p.Code == parameter.Code);
                if (parameterNode != null)
                {
                    parameterNode.Text = srcParameter.Title + " (" + parameter.Code + ")";
                    parameterNode.ToolTipText = srcParameter.Description;
                    this.AutoSave();
                }
                return true;
            }

            return false;
        }

        private bool EditParameter(Parameter parameter, TreeNode parameterNode)
        {
            var oldCode = parameter.Code;
            if (FormEditParameter.EditParameter(parameter))
            {
                
                    TreeViewHelpers.SyncParameter(oldCode, parameter, treeViewTemplates.Nodes, (nodeTemplate, nodeParam, templ, prm) =>
                        {
                            nodeParam.Text = parameter.Title + " (" + parameter.Code + ")";
                            nodeParam.ToolTipText = parameter.Description;
                            prm.Code = parameter.Code;
                        });
                
                if (parameterNode != null)
                {
                    parameterNode.Text = parameter.Title + " (" + parameter.Code + ")";
                    parameterNode.ToolTipText = parameter.Description;
                    this.AutoSave();
                }
                treeViewParameters.Sort();
                return true;
            }
            return false;
        }

        private bool EditTemplate(Template template, TreeNode templateNode)
        {
            string oldName = template.Name;

            if (FormEditTemplate.EditTemplate(this._config, template, this.GetProjects()))
            {
                if (templateNode != null)
                {
                    TreeViewHelpers.SyncTemplate(oldName, templateNode, template, treeViewPresets, _config.Presets, (parentNode, node, parentCat, templName) =>
                        {
                            if (node != null)
                            {
                                node.Text = template.Name;
                                node.Tag = template.Name;
                            }
                            parentCat.RenameTemplate(oldName, template.Name);
                            
                        });
                    templateNode.Text = template.Name;
                    templateNode.ToolTipText = template.Description;

                    treeViewTemplates.Sort();
                    treeViewPresets.Sort();

                    this.AutoSave();
                }
                return true;
            }

            return false;
        }

        private bool EditCategory(Category category, TreeNode categoryNode)
        {
            string oldName = category.Name;

            if (FormEditCategory.EditCategory(category))
            {
                if (categoryNode != null)
                {
                    TreeViewHelpers.SyncCategory(oldName, categoryNode, category, treeViewPresets, _config.Presets, (parentNode, node, parentCat, cat) =>
                        {
                            if (node != null)
                            {
                                node.Text = category.Name;
                                node.ToolTipText = category.Description;
                            }
                            cat.Category = category.Name;
                        });
                
                    categoryNode.Text = category.Name;
                    categoryNode.ToolTipText = category.Description;

                    treeViewTemplates.Sort();
                    treeViewPresets.Sort();

                    this.AutoSave();
                }
                return true;
            }

            return false;
        }

        private void mnuTemplAddRootCat_Click(object sender, EventArgs e)
        {
            var cat = new Category();
            if (EditCategory(cat, null))
            {
                this.AddNodeCategory(treeViewTemplates.Nodes, cat);
                _config.Categories.Add(cat);
                AutoSave();
            }
        }

        private void AutoSave()
        {
            if (_config == null) return;

            try
            {
                if (OnSaveConfig != null)
                    OnSaveConfig(_config);

                _config.Save();
            }
            catch (Exception ex)
            {                
                CommandSet.ShowMessage("Scaffold it! cannot save your modifications. Please check that file is not readonly.");                
            }
        }

        private void mnuTemplAddCategory_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode.Tag is Category)
            {
                var parentcat = treeViewTemplates.SelectedNode.Tag as Category;
                var cat = new Category();
                if (EditCategory(cat, null))
                {
                    this.AddNodeCategory(treeViewTemplates.SelectedNode.Nodes, cat);
                    parentcat.Categories.Add(cat);
                    treeViewTemplates.SelectedNode.Expand();
                    AutoSave();
                }
            }
        }

        private void mnuTemplAddTemplate_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode.Tag is Category)
            {
                var parentcat = treeViewTemplates.SelectedNode.Tag as Category;
                var templ = new Template();
                if (this.EditTemplate(templ, null))
                {
                    this.AddNodeTemplate(treeViewTemplates.SelectedNode.Nodes, templ);
                    parentcat.Templates.Add(templ);
                    treeViewTemplates.SelectedNode.Expand();
                    AutoSave();
                }
            }
        }

        private void mnuTemplRemoveCategory_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode.Tag is Category)
            {
                var cat = treeViewTemplates.SelectedNode.Tag as Category;
                if (MessageBox.Show("Do you really want to remove the category " + cat.Name + " ?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    if (treeViewTemplates.SelectedNode.Parent == null)
                    {
                        TreeViewHelpers.SyncCategory(cat.Name, treeViewTemplates.SelectedNode, cat, treeViewPresets, _config.Presets, (parentNode, node, parentCat, presetcat) =>
                        {
                            treeViewPresets.Nodes.Remove(node);
                            (comboPresets.SelectedItem as Preset).Categories.Remove(presetcat);
                        });
                        _config.Categories.Remove(cat);
                        treeViewTemplates.Nodes.Remove(treeViewTemplates.SelectedNode);
                    }
                    else
                    {
                        TreeViewHelpers.SyncCategory(cat.Name, treeViewTemplates.SelectedNode, cat, treeViewPresets, _config.Presets, (parentNode, node, parentPresetCat, presetcat) =>
                        {
                            if (parentNode != null && node != null)
                                parentNode.Nodes.Remove(node);
                            
                            parentPresetCat.Categories.Remove(presetcat);
                        });
                        var parentCat = treeViewTemplates.SelectedNode.Parent.Tag as Category;
                        parentCat.Categories.Remove(cat);
                        treeViewTemplates.SelectedNode.Parent.Nodes.Remove(treeViewTemplates.SelectedNode);
                    }
                    treeViewTemplates.SelectedNode = null;
                    treeViewTemplates.Sort();
                    treeViewPresets.Sort();
                    this.AutoSave();
                }
            }
        }

        private void mnuTemplRemoveTemplate_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode.Tag is Template)
            {
                var templ = treeViewTemplates.SelectedNode.Tag as Template;
                if (MessageBox.Show("Do you really want to remove the template " + templ.Name + " ?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    var parentCat = treeViewTemplates.SelectedNode.Parent.Tag as Category;
                    TreeViewHelpers.SyncTemplate(templ.Name, treeViewTemplates.SelectedNode, templ, treeViewPresets, _config.Presets, (parentNode, node, parentPresetCat, templName) =>
                    {
                        if (parentNode != null && node != null)
                            parentNode.Nodes.Remove(node);

                        parentPresetCat.RemoveTemplate(templ.Name);
                    });
                    treeViewTemplates.SelectedNode.Parent.Nodes.Remove(treeViewTemplates.SelectedNode);
                    parentCat.Templates.Remove(templ);
                    treeViewTemplates.SelectedNode = null;
                    treeViewTemplates.Sort();
                    treeViewPresets.Sort();
                    this.AutoSave();
                }
            }
        }

        private void mnuTemplRemoveParameter_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode.Tag is Parameter)
            {
                var parameter = treeViewTemplates.SelectedNode.Tag as Parameter;
                var templ = treeViewTemplates.SelectedNode.Parent.Tag as Template;
                if (MessageBox.Show("Do you really want to remove the parameter " + parameter.Code + " ?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    treeViewTemplates.SelectedNode.Parent.Nodes.Remove(treeViewTemplates.SelectedNode);
                    templ.Parameters.Remove(parameter);
                    treeViewTemplates.Sort();
                    treeViewTemplates.SelectedNode = null;
                    this.AutoSave();
                }
            }
        }

        private void mnuTemplEdit_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode != null)
            {
                if (treeViewTemplates.SelectedNode.Tag is Category)
                {
                    var category = treeViewTemplates.SelectedNode.Tag as Category;
                    EditCategory(category, treeViewTemplates.SelectedNode);
                }
                if (treeViewTemplates.SelectedNode.Tag is Template)
                {
                    var template = treeViewTemplates.SelectedNode.Tag as Template;
                    EditTemplate(template, treeViewTemplates.SelectedNode);
                }
                if (treeViewTemplates.SelectedNode.Tag is Parameter)
                {
                    var parameter = treeViewTemplates.SelectedNode.Tag as Parameter;
                    EditTemplateParameter(parameter, treeViewTemplates.SelectedNode);
                }
            }
        }

        private void mnuPresetsRemove_Click(object sender, EventArgs e)
        {
            if (treeViewPresets.SelectedNode.Tag is PresetCategory)
            {
                var cat = treeViewPresets.SelectedNode.Tag as PresetCategory;
                if (
                    MessageBox.Show(
                        "Do you really want to remove the preset category " + cat.Category + " ?",
                        "Confirm",
                        MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    if (treeViewPresets.SelectedNode.Parent != null)
                    {
                        var parentCat = treeViewPresets.SelectedNode.Parent.Tag as PresetCategory;
                        parentCat.Categories.Remove(cat);
                        treeViewPresets.SelectedNode.Parent.Nodes.Remove(treeViewPresets.SelectedNode);
                    }
                    else
                    {
                        treeViewPresets.Nodes.Remove(treeViewPresets.SelectedNode);
                        var preset = comboPresets.SelectedItem as Preset;
                        preset.Categories.Remove(cat);
                    }
                    this.AutoSave();
                }
            }
            else if (treeViewPresets.SelectedNode.Tag is string)
            {
                var templName = treeViewPresets.SelectedNode.Tag as string;
                var cat = treeViewPresets.SelectedNode.Parent.Tag as PresetCategory;
                if (
                    MessageBox.Show(
                        "Do you really want to remove the template " + templName + "  from this preset ?",
                        "Confirm",
                        MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    treeViewPresets.SelectedNode.Parent.Nodes.Remove(treeViewPresets.SelectedNode);
                    cat.RemoveTemplate(templName);
                    this.AutoSave();
                }
            }
        }

        private void ctxMenuTreePresets_Opening(object sender, CancelEventArgs e)
        {
            mnuPresetsRemove.Visible = false;
            if (comboPresets.SelectedItem != null && treeViewPresets.SelectedNode != null)
            {
                mnuPresetsRemove.Visible = true;
            }
        }

        private void imgAddPreset_Click(object sender, EventArgs e)
        {
            var preset = new Preset();
            if (FormEditPreset.EditPreset(preset))
            {
                _config.Presets.Add(preset);
                comboPresets.Items.Add(preset);
                comboPresets.Sorted = true;
                comboPresets.SelectedItem = preset;
                this.AutoSave();
            }
        }

        private void imgEditPreset_Click(object sender, EventArgs e)
        {
            var preset = comboPresets.SelectedItem as Preset;
            if (preset != null && FormEditPreset.EditPreset(preset))
            {
                this.AutoSave();
            }
        }

        private void imgDeletePreset_Click(object sender, EventArgs e)
        {
            var preset = comboPresets.SelectedItem as Preset;
            if (preset != null &&
                    MessageBox.Show(
                        "Do you really want to remove the preset " + preset.Name + " ?",
                        "Confirm",
                        MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                _config.Presets.Remove(preset);
                comboPresets.Items.Remove(preset);
                comboPresets.Sorted = true;
                treeViewPresets.Nodes.Clear();
                this.AutoSave();
            }
        }

        private void mnuParamsAddParameter_Click(object sender, EventArgs e)
        {

            var prm = new Parameter();
            if (this.EditParameter(prm, null))
            {
                this.AddRootParameter(prm);
                _config.Parameters.Add(prm);
                AutoSave();
            }
        }

        private void mnuParamsEdit_Click(object sender, EventArgs e)
        {
            if (treeViewParameters.SelectedNode != null)
            {
                var parameter = treeViewParameters.SelectedNode.Tag as Parameter;
                EditParameter(parameter, treeViewParameters.SelectedNode);
            }
        }

        private void mnuParamsRemove_Click(object sender, EventArgs e)
        {
            if (treeViewParameters.SelectedNode != null)
            {
                var parameter = treeViewParameters.SelectedNode.Tag as Parameter;

                if (MessageBox.Show("Do you really want to remove the parameter " + parameter.Code + " ?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    treeViewParameters.Nodes.Remove(treeViewParameters.SelectedNode);
                    _config.Parameters.Remove(parameter);
                    TreeViewHelpers.SyncParameter(parameter.Code, parameter, treeViewTemplates.Nodes, (tempnode, prmnode, template, prm) =>
                        {
                            tempnode.Nodes.Remove(prmnode);
                            template.Parameters.Remove(prm);
                        });
                    this.AutoSave();
                }
            }
        }

        private TreeNode lastNodeShown;
        private void treeView_MouseMove(object sender, MouseEventArgs e)
        {
            //Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
            var tree = (TreeView)sender;
            Point pt = new Point(e.X, e.Y);
            var node = tree.GetNodeAt(pt);
            if (node != null)
            {
                if (node != lastNodeShown)
                {
                    var ptScreen = tree.PointToScreen(pt);
                    var ptToolTip = this.PointToClient(ptScreen);
                    
                    lastNodeShown = node;

                    toolTip1.Show(node.ToolTipText, this, ptToolTip.X + 10, ptToolTip.Y + (int)(tree.Font.Height * 1.3));
                }                
            }
            else
            {
                toolTip1.Show(string.Empty, this, 0, 0);
            }
        }

        private void mnuTemplView_Click(object sender, EventArgs e)
        {
            if (treeViewTemplates.SelectedNode != null && treeViewTemplates.SelectedNode.Tag is Template)
            {
                var template = treeViewTemplates.SelectedNode.Tag as Template;
                if (OnOpenFile != null) 
                    OnOpenFile(template.TemplateName);
            }
        }
    }
}
